package org.delphy.indy2.containers
{
	import caurina.transitions.Tweener;
	
	import flash.display.DisplayObject;
	import flash.events.Event;
	import flash.events.MouseEvent;
	import flash.utils.Dictionary;
	
	import mx.containers.HBox;
	import mx.core.Container;
	import mx.core.UIComponent;
	import mx.styles.StyleManager;
	
	import org.delphy.indy2.core.ICarbonComponent;
	import org.delphy.indy2.layers.FilterFactory;

	//----------------------------------
	//  Styles
	//----------------------------------	
	
	/**
	 *	Top-left corner radius
	 *	
	 *	@default 0
	 */
	[Style(name="topLeftRadius", type="Number", format="Length", inherit="no")]
	
	/**
	 *	Top-right corner radius
	 *	
	 *	@default 0
	 */
	[Style(name="topRightRadius", type="Number", format="Length", inherit="no")]
	
	/**
	 *	Bottom-left corner radius
	 *	
	 *	@default 0
	 */
	[Style(name="bottomLeftRadius", type="Number", format="Length", inherit="no")]
	
	/**
	 *	Bottom-right corner radius
	 *	
	 *	@default 0
	 */
	[Style(name="bottomRightRadius", type="Number", format="Length", inherit="no")]
	
	/**
	 * FilterLayer
	 * This is a dummy canvas for hosting filters 
	 * 
	 * @default: carbonPanelShadowFilter
	 */
	[Style(name="filterLayer", type="String", inherit="no")]
	
	/**
	 * Backbround Colors
	 * 
	 * @default #000000, #000000
	 */
	[Style(name="backgroundColors", type="Array", arrayType="Number", inherit="no")]
	
	/**
	 * Backbround Alphas
	 * 
	 * @default 0.85, 0.45
	 */
	[Style(name="backgroundAlphas", type="Array", arrayType="Number", inherit="no")]
	
	/**
	 * Backbround Ratios
	 */
	[Style(name="backgroundRatios", type="Array", arrayType="Number", inherit="no")]
	
	/**
	 * Backbround RatioUnits
	 */
	[Style(name="backgroundRatioUnits", type="Array", arrayType="String", inherit="no")]
	
	/**
	 * Border Colors
	 * 
	 * @default #000000, #000000
	 */
	[Style(name="borderColors", type="Array", arrayType="Number", inherit="no")]
	
	/**
	 * Border Alphas
	 */
	[Style(name="borderAlphas", type="Array", arrayType="Number", inherit="no")]
	
	/**
	 * Border Ratios
	 */
	[Style(name="borderRatios", type="Array", arrayType="Number", inherit="no")]
	
	/**
	 * Border RatioUnits
	 */
	[Style(name="borderRatioUnits", type="Array", arrayType="String", inherit="no")]
	
	/**
	 * Border Weight
	 * 
	 * @default 1
	 */
	[Style(name="borderWeight", type="Number", inherit="no")]
	
	/**
	 * Border Highlight Colors
	 * 
	 * @default #000000, #FFFFFF, #000000
	 */
	[Style(name="borderHighlightColors", type="Array", arrayType="Number", inherit="no")]
	
	/**
	 * Border Highlight Alphas
	 * 
	 * @defaut 0, 0.8, 0
	 */
	[Style(name="borderHighlightAlphas", type="Array", arrayType="Number", inherit="no")]
	
	/**
	 * Border  Highlight Ratios
	 */
	[Style(name="borderHighlightRatios", type="Array", arrayType="Number", inherit="no")]
	
	/**
	 * Border Highlight RatioUnits
	 */
	[Style(name="borderHighlightRatioUnits", type="Array", arrayType="String", inherit="no")]
	
	/**
	 * Whether to draw a horizontal highlight on border
	 * 
	 * @default true
	 */
	[Style(name="useHBorderHighlight", type="Boolean", inherit="no")]	
	
	/**
	 * Whether to draw a vertal highlight on border
	 * 
	 * @default true
	 */
	[Style(name="useVBorderHighlight", type="Boolean", inherit="no")]	

	public class CarbonTabDock extends HBox implements ICarbonComponent
	{
		//--------------------------------------
		//  Animation and status
		//--------------------------------------
		
		/**
		 * @public
		 * 
		 * @default 1
		 */
		public var transitionTime:Number=1;
		
		/**
		 * @protected
		 */
		protected var resizing:Boolean=false;
		
		/**
		 * @protected
		 */
		protected static const EXPAND_ACTION:String="expand";

		/**
		 * @protected
		 */
		protected static const SHRINK_ACTION:String="shrink";

		//----------------------------------
		//  Geometry
		//----------------------------------
		
		/**
		 * @protected
		 * 
		 * @default 0
		 */
		protected var _topLeftRadius:Number;
		
		/**
		 * @protected
		 * 
		 * @default 0
		 */
		protected var _topRightRadius:Number;
		
		/**
		 * @protected
		 * 
		 * @default 12
		 */
		protected var _bottomLeftRadius:Number;
		
		/**
		 * @protected
		 * 
		 * @default 12
		 */
		protected var _bottomRightRadius:Number;
		
		/**
		 * @protected
		 * 
		 * @default 1
		 */
		protected var _borderWeight:Number;
		
		//--------------------------------------
		//  Content
		//--------------------------------------
		
		/**
		 * @public
		 */
		public var contentByWidget:Dictionary;
		
		/**
		 * @public
		 */
		public var statusByWidget:Dictionary;
		
		/**
		 * @private
		 * This is used in the overridden function addChild() 
		 */
		protected var lastAddedChild:DisplayObject;
		
		/**
		 * @private
		 * This is used in the overridden function addChild()
		 */
		protected var numChildrenAdded:Number=0;

		//--------------------------------------
		//  Methods
		//--------------------------------------
		
		/**
		 * Constructor
		 */
		public function CarbonTabDock()
		{
			super();
			
			horizontalScrollPolicy="off";
			verticalScrollPolicy="off";
			
			contentByWidget=new Dictionary();
			statusByWidget=new Dictionary();
		}

		/**
		 * @protected
		 */
		override protected function createChildren() : void{
			super.createChildren();
			if(!styleName)
				styleName="carbonTabDock";			
		}
		
		/**
		 * @public
		 * addChild() will handle two different objects: "widgets" and "contents".
		 * A widget will always follow by a content, that means, even objects are always
		 * widgets, while odd objects are treated as contents.
		 * 
		 * Widgets are registered with MouseEvent.CLICK event. Click them will expend or shrink
		 * the content follows.
		 */
		override public function addChild(child:DisplayObject) : DisplayObject{
			if(numChildrenAdded % 2 == 1){
				// If child is a content
				contentByWidget[lastAddedChild]=child;
				child.width=0;
				
				// Force hiding scrollbars to avoid embrassment while playing animation
				if(child is Container){
					Container(child).horizontalScrollPolicy="off";
					Container(child).verticalScrollPolicy="off";
				}
			}
			else{
				// Otherwise, it's a widget
				statusByWidget[child]=false;
				child.addEventListener(MouseEvent.ROLL_OVER,onWidgetRollOver);
				child.addEventListener(MouseEvent.ROLL_OUT,onWidgetRollOut);
				child.addEventListener(MouseEvent.CLICK,onWidgetClick);				
			}
			
			numChildrenAdded++;
			lastAddedChild=child;
			return super.addChild(child);
		}
		
		/**
		 * @public
		 * This is the old way of adding widget-content pairs in Indy2 1.0
		 */
		public function addWidget(obj:Object):void{
			// The widget to be added to the dock is of type "Object". It should contain two entries:
			// obj:{widget:UIComponent,content:UIComponent}
			
			var widget:UIComponent=obj.widget;
			var content:UIComponent=obj.content;

			addChild(widget);
			addChild(content);
		} 
		
		/**
		 * @protected
		 * Event handler for MouseEvent.ROLL_OVER
		 */
		protected function onWidgetRollOver(evt:MouseEvent):void{
			var widget:UIComponent=evt.currentTarget as UIComponent;
			if(!statusByWidget[widget])
				expandDockWithTarget(widget);
		}
		
		/**
		 * @protected
		 * Event handler for MouseEvent.ROLL_OUT
		 */
		protected function onWidgetRollOut(evt:MouseEvent):void{
			var widget:UIComponent=evt.currentTarget as UIComponent;
			if(!statusByWidget[widget])
				shrinkDockWithTarget(widget);
		}
		
		/**
		 * @protected
		 * Event handler for MouseEvent.CLICK
		 */		
		protected function onWidgetClick(evt:MouseEvent):void{
			pinWidget(evt.currentTarget as UIComponent);
		}
		
		/**
		 * @protected
		 */
		protected function expandDockWithTarget(target:UIComponent):void{
			var content:UIComponent=contentByWidget[target];
			var contentFullWidth:Number=content.measuredWidth;
			
			// If necessary, resize the dock
			resizeDock(content,EXPAND_ACTION);
			
			Tweener.addTween(content,{width:contentFullWidth,time:transitionTime});
		}
		
		/**
		 * @protected
		 */		
		protected function shrinkDockWithTarget(target:UIComponent):void{
			var content:UIComponent=contentByWidget[target];
			var contentFullWidth:Number=content.measuredWidth;
			
			// If necessary, resize the dock
			resizeDock(content,SHRINK_ACTION);
			
			Tweener.addTween(content,{width:0,time:transitionTime});		
		}

		/**
		 * @protected
		 * Adjust the size and layout of the dock
		 */
		protected function resizeDock(currentContent:UIComponent=null,currentAction:String=null):void{
			var expectedWidth:Number=0;
			
			for each(var child:UIComponent in this.getChildren()){
				if(child==currentContent){
					if(currentAction==EXPAND_ACTION)
						expectedWidth+=child.measuredWidth;
					else if(currentAction==SHRINK_ACTION)
						expectedWidth+=0;
				}
				else{
					expectedWidth+=child.width;
				}
				
				expectedWidth+=getStyle("horizontalGap");
			}
						
			Tweener.addTween(this,{width:expectedWidth,time:transitionTime,onComplete:onDockResizeComplete});
			resizing=true;
		}
		
		/**
		 * @protected
		 * Event handler for resize complete
		 */		
		protected function onDockResizeComplete(evt:Event=null):void{
			resizing=false;
		}
		
		/**
		 * @protected
		 */
		protected function pinWidget(target:UIComponent):void{
			statusByWidget[target]=!statusByWidget[target];
		}
		
		/**
		 * @protected
		 */
		override protected function updateDisplayList(unscaledWidth:Number, unscaledHeight:Number) : void{
			super.updateDisplayList(unscaledWidth, unscaledHeight);
			
			resizeDock();
			
			filters=FilterFactory.createFilters(this);
		}
		
		/**
		 * @public
		 */
		public function get defaultStyleName():String{
			return "carbonTabDock";
		}
	}
}